package org.breathe.dynamic.thread.pool.core.notify.alarm;

import cn.hutool.core.util.StrUtil;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.breathe.dynamic.thread.pool.core.thread.BreatheDtpExecutor;
import org.breathe.thread.pool.common.entity.NotifyItem;
import org.breathe.thread.pool.common.enums.NotifyTypeEnum;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 警报频率限制
 * @author: breathe
 * @createTime: 2025-04-10
 */
public class AlarmLimiter {
    /**
     * 存储线程池报警的频率限制信息
     */
    private static final Map<String, Cache<String, String>> ALARM_LIMITER = new ConcurrentHashMap<>();
    private AlarmLimiter() {}

    /**
     * 构建Key
     * @param breatheDtpName 线程池名称
     * @param type 报警类型
     * @return 返回key
     */
    public static String buildOuterKey(String breatheDtpName, String type) {
        return breatheDtpName + ":" + type;
    }

    /**
     * 初始化报警频率限制
     * @param breatheDtpName 名字
     * @param notifyItem 通知实体
     */
    public static void initAlarmLimiter(String breatheDtpName, NotifyItem notifyItem) {
        //如果他为change的话，就结束
        if (NotifyTypeEnum.CHANGE.getValue().equalsIgnoreCase(notifyItem.getType())) {
            return ;
        }
        //创建一个线程池的报警类型，然后将他放入限制器中
        String outerKey = buildOuterKey(breatheDtpName, notifyItem.getType());
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .expireAfterAccess(notifyItem.getInterval(), TimeUnit.SECONDS)
                .build();
        ALARM_LIMITER.put(outerKey, cache);
    }

    /**
     * 向缓存中插入报警类型
     * @param executor 线程池
     * @param type 报警类型
     */
    public static void putVal(BreatheDtpExecutor executor, String type) {
        String outerKey = buildOuterKey(executor.getThreadPoolName(), type);
        ALARM_LIMITER.get(outerKey).put(type, type);
    }

    /**
     * 从缓存中获取报警信息
     * @param outerKey key
     * @param innerKey 内部的key，因为有个cache结构，所以想获取报警信息的话得获取两次
     * @return 返回报警类型
     */
    public static String getAlarmLimitInfo(String outerKey, String innerKey) {
        return ALARM_LIMITER.get(outerKey).getIfPresent(innerKey);
    }

    /**
     * 判断是否需要发送报警信息
     * @param executor 线程池
     * @param type 报警类型
     * @return
     */
    public static boolean ifAlarm(BreatheDtpExecutor executor, String type) {
        String key = buildOuterKey(executor.getThreadPoolName(), type);
        //如果缓存中不存在改信息，就需要发送报警信息，否则不需要发送报警信息。
        return StrUtil.isBlank(getAlarmLimitInfo(key, type));
    }
}
